/**
 * Copyright (c) 2014-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const regeneratorRuntime = (function (exports) {
  const Op = Object.prototype
  const hasOwn = Op.hasOwnProperty
  let undefined // More compressible than void 0.
  const $Symbol = typeof Symbol === 'function' ? Symbol : {}
  const iteratorSymbol = $Symbol.iterator || '@@iterator'
  const asyncIteratorSymbol = $Symbol.asyncIterator || '@@asyncIterator'
  const toStringTagSymbol = $Symbol.toStringTag || '@@toStringTag'

  function wrap(innerFn, outerFn, self, tryLocsList) {
    // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
    const protoGenerator =
      outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator
    const generator = Object.create(protoGenerator.prototype)
    const context = new Context(tryLocsList || [])

    // The ._invoke method unifies the implementations of the .next,
    // .throw, and .return methods.
    generator._invoke = makeInvokeMethod(innerFn, self, context)

    return generator
  }
  exports.wrap = wrap

  // Try/catch helper to minimize deoptimizations. Returns a completion
  // record like context.tryEntries[i].completion. This interface could
  // have been (and was previously) designed to take a closure to be
  // invoked without arguments, but in all the cases we care about we
  // already have an existing method we want to call, so there's no need
  // to create a new function object. We can even get away with assuming
  // the method takes exactly one argument, since that happens to be true
  // in every case, so we don't have to touch the arguments object. The
  // only additional allocation required is the completion record, which
  // has a stable shape and so hopefully should be cheap to allocate.
  function tryCatch(fn, obj, arg) {
    try {
      return { type: 'normal', arg: fn.call(obj, arg) }
    } catch (err) {
      return { type: 'throw', arg: err }
    }
  }

  const GenStateSuspendedStart = 'suspendedStart'
  const GenStateSuspendedYield = 'suspendedYield'
  const GenStateExecuting = 'executing'
  const GenStateCompleted = 'completed'

  // Returning this object from the innerFn has the same effect as
  // breaking out of the dispatch switch statement.
  const ContinueSentinel = {}

  // Dummy constructor functions that we use as the .constructor and
  // .constructor.prototype properties for functions that return Generator
  // objects. For full spec compliance, you may wish to configure your
  // minifier not to mangle the names of these two functions.
  function Generator() {}
  function GeneratorFunction() {}
  function GeneratorFunctionPrototype() {}

  // This is a polyfill for %IteratorPrototype% for environments that
  // don't natively support it.
  let IteratorPrototype = {}
  IteratorPrototype[iteratorSymbol] = function () {
    return this
  }

  const getProto = Object.getPrototypeOf
  const NativeIteratorPrototype = getProto && getProto(getProto(values([])))
  if (
    NativeIteratorPrototype &&
    NativeIteratorPrototype !== Op &&
    hasOwn.call(NativeIteratorPrototype, iteratorSymbol)
  ) {
    // This environment has a native %IteratorPrototype%; use it instead
    // of the polyfill.
    IteratorPrototype = NativeIteratorPrototype
  }

  const Gp = (GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype))
  GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype
  GeneratorFunctionPrototype.constructor = GeneratorFunction
  GeneratorFunctionPrototype[
    toStringTagSymbol
  ] = GeneratorFunction.displayName = 'GeneratorFunction'

  // Helper for defining the .next, .throw, and .return methods of the
  // Iterator interface in terms of a single ._invoke method.
  function defineIteratorMethods(prototype) {
    ['next', 'throw', 'return'].forEach((method) => {
      prototype[method] = function (arg) {
        return this._invoke(method, arg)
      }
    })
  }

  exports.isGeneratorFunction = function (genFun) {
    const ctor = typeof genFun === 'function' && genFun.constructor
    return ctor
      ? ctor === GeneratorFunction ||
          // For the native GeneratorFunction constructor, the best we can
          // do is to check its .name property.
          (ctor.displayName || ctor.name) === 'GeneratorFunction'
      : false
  }

  exports.mark = function (genFun) {
    if (Object.setPrototypeOf) {
      Object.setPrototypeOf(genFun, GeneratorFunctionPrototype)
    } else {
      genFun.__proto__ = GeneratorFunctionPrototype
      if (!(toStringTagSymbol in genFun)) {
        genFun[toStringTagSymbol] = 'GeneratorFunction'
      }
    }
    genFun.prototype = Object.create(Gp)
    return genFun
  }

  // Within the body of any async function, `await x` is transformed to
  // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
  // `hasOwn.call(value, "__await")` to determine if the yielded value is
  // meant to be awaited.
  exports.awrap = function (arg) {
    return { __await: arg }
  }

  function AsyncIterator(generator) {
    function invoke(method, arg, resolve, reject) {
      const record = tryCatch(generator[method], generator, arg)
      if (record.type === 'throw') {
        reject(record.arg)
      } else {
        const result = record.arg
        const value = result.value
        if (
          value &&
          typeof value === 'object' &&
          hasOwn.call(value, '__await')
        ) {
          return Promise.resolve(value.__await).then(
            (value) => {
              invoke('next', value, resolve, reject)
            },
            (err) => {
              invoke('throw', err, resolve, reject)
            }
          )
        }

        return Promise.resolve(value).then(
          (unwrapped) => {
            // When a yielded Promise is resolved, its final value becomes
            // the .value of the Promise<{value,done}> result for the
            // current iteration.
            result.value = unwrapped
            resolve(result)
          },
          (error) =>
            // If a rejected Promise was yielded, throw the rejection back
            // into the async generator function so it can be handled there.
            invoke('throw', error, resolve, reject)

        )
      }
    }

    let previousPromise

    function enqueue(method, arg) {
      function callInvokeWithMethodAndArg() {
        return new Promise(((resolve, reject) => {
          invoke(method, arg, resolve, reject)
        }))
      }

      return (previousPromise =
        // If enqueue has been called before, then we want to wait until
        // all previous Promises have been resolved before calling invoke,
        // so that results are always delivered in the correct order. If
        // enqueue has not been called before, then it is important to
        // call invoke immediately, without waiting on a callback to fire,
        // so that the async generator function has the opportunity to do
        // any necessary setup in a predictable way. This predictability
        // is why the Promise constructor synchronously invokes its
        // executor callback, and why async functions synchronously
        // execute code before the first await. Since we implement simple
        // async functions in terms of async generators, it is especially
        // important to get this right, even though it requires care.
        previousPromise
          ? previousPromise.then(
            callInvokeWithMethodAndArg,
            // Avoid propagating failures to Promises returned by later
            // invocations of the iterator.
            callInvokeWithMethodAndArg
          )
          : callInvokeWithMethodAndArg())
    }

    // Define the unified helper method that is used to implement .next,
    // .throw, and .return (see defineIteratorMethods).
    this._invoke = enqueue
  }

  defineIteratorMethods(AsyncIterator.prototype)
  AsyncIterator.prototype[asyncIteratorSymbol] = function () {
    return this
  }
  exports.AsyncIterator = AsyncIterator

  // Note that simple async functions are implemented on top of
  // AsyncIterator objects; they just return a Promise for the value of
  // the final result produced by the iterator.
  exports.async = function (innerFn, outerFn, self, tryLocsList) {
    const iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList))

    return exports.isGeneratorFunction(outerFn)
      ? iter // If outerFn is a generator, return the full iterator.
      : iter.next().then((result) => (result.done ? result.value : iter.next()))
  }

  function makeInvokeMethod(innerFn, self, context) {
    let state = GenStateSuspendedStart

    return function invoke(method, arg) {
      if (state === GenStateExecuting) {
        throw new Error('Generator is already running')
      }

      if (state === GenStateCompleted) {
        if (method === 'throw') {
          throw arg
        }

        // Be forgiving, per 25.3.3.3.3 of the spec:
        // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
        return doneResult()
      }

      context.method = method
      context.arg = arg

      while (true) {
        const delegate = context.delegate
        if (delegate) {
          const delegateResult = maybeInvokeDelegate(delegate, context)
          if (delegateResult) {
            if (delegateResult === ContinueSentinel) continue
            return delegateResult
          }
        }

        if (context.method === 'next') {
          // Setting context._sent for legacy support of Babel's
          // function.sent implementation.
          context.sent = context._sent = context.arg
        } else if (context.method === 'throw') {
          if (state === GenStateSuspendedStart) {
            state = GenStateCompleted
            throw context.arg
          }

          context.dispatchException(context.arg)
        } else if (context.method === 'return') {
          context.abrupt('return', context.arg)
        }

        state = GenStateExecuting

        const record = tryCatch(innerFn, self, context)
        if (record.type === 'normal') {
          // If an exception is thrown from innerFn, we leave state ===
          // GenStateExecuting and loop back for another invocation.
          state = context.done ? GenStateCompleted : GenStateSuspendedYield

          if (record.arg === ContinueSentinel) {
            continue
          }

          return {
            value: record.arg,
            done: context.done
          }
        } else if (record.type === 'throw') {
          state = GenStateCompleted
          // Dispatch the exception by looping back around to the
          // context.dispatchException(context.arg) call above.
          context.method = 'throw'
          context.arg = record.arg
        }
      }
    }
  }

  // Call delegate.iterator[context.method](context.arg) and handle the
  // result, either by returning a { value, done } result from the
  // delegate iterator, or by modifying context.method and context.arg,
  // setting context.delegate to null, and returning the ContinueSentinel.
  function maybeInvokeDelegate(delegate, context) {
    const method = delegate.iterator[context.method]
    if (method === undefined) {
      // A .throw or .return when the delegate iterator has no .throw
      // method always terminates the yield* loop.
      context.delegate = null

      if (context.method === 'throw') {
        if (delegate.iterator.return) {
          // If the delegate iterator has a return method, give it a
          // chance to clean up.
          context.method = 'return'
          context.arg = undefined
          maybeInvokeDelegate(delegate, context)

          if (context.method === 'throw') {
            // If maybeInvokeDelegate(context) changed context.method from
            // "return" to "throw", let that override the TypeError below.
            return ContinueSentinel
          }
        }

        context.method = 'throw'
        context.arg = new TypeError("The iterator does not provide a 'throw' method")
      }

      return ContinueSentinel
    }

    const record = tryCatch(method, delegate.iterator, context.arg)

    if (record.type === 'throw') {
      context.method = 'throw'
      context.arg = record.arg
      context.delegate = null
      return ContinueSentinel
    }

    const info = record.arg

    if (!info) {
      context.method = 'throw'
      context.arg = new TypeError('iterator result is not an object')
      context.delegate = null
      return ContinueSentinel
    }

    if (info.done) {
      // Assign the result of the finished delegate to the temporary
      // variable specified by delegate.resultName (see delegateYield).
      context[delegate.resultName] = info.value

      // Resume execution at the desired location (see delegateYield).
      context.next = delegate.nextLoc

      // If context.method was "throw" but the delegate handled the
      // exception, let the outer generator proceed normally. If
      // context.method was "next", forget context.arg since it has been
      // "consumed" by the delegate iterator. If context.method was
      // "return", allow the original .return call to continue in the
      // outer generator.
      if (context.method !== 'return') {
        context.method = 'next'
        context.arg = undefined
      }
    } else {
      // Re-yield the result returned by the delegate method.
      return info
    }

    // The delegate iterator is finished, so forget it and continue with
    // the outer generator.
    context.delegate = null
    return ContinueSentinel
  }

  // Define Generator.prototype.{next,throw,return} in terms of the
  // unified ._invoke helper method.
  defineIteratorMethods(Gp)

  Gp[toStringTagSymbol] = 'Generator'

  // A Generator should always return itself as the iterator object when the
  // @@iterator function is called on it. Some browsers' implementations of the
  // iterator prototype chain incorrectly implement this, causing the Generator
  // object to not be returned from this call. This ensures that doesn't happen.
  // See https://github.com/facebook/regenerator/issues/274 for more details.
  Gp[iteratorSymbol] = function () {
    return this
  }

  Gp.toString = function () {
    return '[object Generator]'
  }

  function pushTryEntry(locs) {
    const entry = { tryLoc: locs[0] }

    if (1 in locs) {
      entry.catchLoc = locs[1]
    }

    if (2 in locs) {
      entry.finallyLoc = locs[2]
      entry.afterLoc = locs[3]
    }

    this.tryEntries.push(entry)
  }

  function resetTryEntry(entry) {
    const record = entry.completion || {}
    record.type = 'normal'
    delete record.arg
    entry.completion = record
  }

  function Context(tryLocsList) {
    // The root entry object (effectively a try statement without a catch
    // or a finally block) gives us a place to store values thrown from
    // locations where there is no enclosing try statement.
    this.tryEntries = [{ tryLoc: 'root' }]
    tryLocsList.forEach(pushTryEntry, this)
    this.reset(true)
  }

  exports.keys = function (object) {
    const keys = []
    for (const key in object) {
      keys.push(key)
    }
    keys.reverse()

    // Rather than returning an object with a next method, we keep
    // things simple and return the next function itself.
    return function next() {
      while (keys.length) {
        const key = keys.pop()
        if (key in object) {
          next.value = key
          next.done = false
          return next
        }
      }

      // To avoid creating an additional object, we just hang the .value
      // and .done properties off the next function object itself. This
      // also ensures that the minifier will not anonymize the function.
      next.done = true
      return next
    }
  }

  function values(iterable) {
    if (iterable) {
      const iteratorMethod = iterable[iteratorSymbol]
      if (iteratorMethod) {
        return iteratorMethod.call(iterable)
      }

      if (typeof iterable.next === 'function') {
        return iterable
      }

      if (!isNaN(iterable.length)) {
        let i = -1,
          next = function next() {
            while (++i < iterable.length) {
              if (hasOwn.call(iterable, i)) {
                next.value = iterable[i]
                next.done = false
                return next
              }
            }

            next.value = undefined
            next.done = true

            return next
          }

        return (next.next = next)
      }
    }

    // Return an iterator with no values.
    return { next: doneResult }
  }
  exports.values = values

  function doneResult() {
    return { value: undefined, done: true }
  }

  Context.prototype = {
    constructor: Context,

    reset(skipTempReset) {
      this.prev = 0
      this.next = 0
      // Resetting context._sent for legacy support of Babel's
      // function.sent implementation.
      this.sent = this._sent = undefined
      this.done = false
      this.delegate = null

      this.method = 'next'
      this.arg = undefined

      this.tryEntries.forEach(resetTryEntry)

      if (!skipTempReset) {
        for (const name in this) {
          // Not sure about the optimal order of these conditions:
          if (
            name.charAt(0) === 't' &&
            hasOwn.call(this, name) &&
            !isNaN(+name.slice(1))
          ) {
            this[name] = undefined
          }
        }
      }
    },

    stop() {
      this.done = true

      const rootEntry = this.tryEntries[0]
      const rootRecord = rootEntry.completion
      if (rootRecord.type === 'throw') {
        throw rootRecord.arg
      }

      return this.rval
    },

    dispatchException(exception) {
      if (this.done) {
        throw exception
      }

      const context = this
      function handle(loc, caught) {
        record.type = 'throw'
        record.arg = exception
        context.next = loc

        if (caught) {
          // If the dispatched exception was caught by a catch block,
          // then let that catch block handle the exception normally.
          context.method = 'next'
          context.arg = undefined
        }

        return !!caught
      }

      for (let i = this.tryEntries.length - 1; i >= 0; --i) {
        const entry = this.tryEntries[i]
        var record = entry.completion

        if (entry.tryLoc === 'root') {
          // Exception thrown outside of any try block that could handle
          // it, so set the completion value of the entire function to
          // throw the exception.
          return handle('end')
        }

        if (entry.tryLoc <= this.prev) {
          const hasCatch = hasOwn.call(entry, 'catchLoc')
          const hasFinally = hasOwn.call(entry, 'finallyLoc')

          if (hasCatch && hasFinally) {
            if (this.prev < entry.catchLoc) {
              return handle(entry.catchLoc, true)
            } else if (this.prev < entry.finallyLoc) {
              return handle(entry.finallyLoc)
            }
          } else if (hasCatch) {
            if (this.prev < entry.catchLoc) {
              return handle(entry.catchLoc, true)
            }
          } else if (hasFinally) {
            if (this.prev < entry.finallyLoc) {
              return handle(entry.finallyLoc)
            }
          } else {
            throw new Error('try statement without catch or finally')
          }
        }
      }
    },

    abrupt(type, arg) {
      for (let i = this.tryEntries.length - 1; i >= 0; --i) {
        const entry = this.tryEntries[i]
        if (
          entry.tryLoc <= this.prev &&
          hasOwn.call(entry, 'finallyLoc') &&
          this.prev < entry.finallyLoc
        ) {
          var finallyEntry = entry
          break
        }
      }

      if (
        finallyEntry &&
        (type === 'break' || type === 'continue') &&
        finallyEntry.tryLoc <= arg &&
        arg <= finallyEntry.finallyLoc
      ) {
        // Ignore the finally entry if control is not jumping to a
        // location outside the try/catch block.
        finallyEntry = null
      }

      const record = finallyEntry ? finallyEntry.completion : {}
      record.type = type
      record.arg = arg

      if (finallyEntry) {
        this.method = 'next'
        this.next = finallyEntry.finallyLoc
        return ContinueSentinel
      }

      return this.complete(record)
    },

    complete(record, afterLoc) {
      if (record.type === 'throw') {
        throw record.arg
      }

      if (record.type === 'break' || record.type === 'continue') {
        this.next = record.arg
      } else if (record.type === 'return') {
        this.rval = this.arg = record.arg
        this.method = 'return'
        this.next = 'end'
      } else if (record.type === 'normal' && afterLoc) {
        this.next = afterLoc
      }

      return ContinueSentinel
    },

    finish(finallyLoc) {
      for (let i = this.tryEntries.length - 1; i >= 0; --i) {
        const entry = this.tryEntries[i]
        if (entry.finallyLoc === finallyLoc) {
          this.complete(entry.completion, entry.afterLoc)
          resetTryEntry(entry)
          return ContinueSentinel
        }
      }
    },

    catch(tryLoc) {
      for (let i = this.tryEntries.length - 1; i >= 0; --i) {
        const entry = this.tryEntries[i]
        if (entry.tryLoc === tryLoc) {
          const record = entry.completion
          if (record.type === 'throw') {
            var thrown = record.arg
            resetTryEntry(entry)
          }
          return thrown
        }
      }

      // The context.catch method must only be called with a location
      // argument that corresponds to a known catch block.
      throw new Error('illegal catch attempt')
    },

    delegateYield(iterable, resultName, nextLoc) {
      this.delegate = {
        iterator: values(iterable),
        resultName,
        nextLoc
      }

      if (this.method === 'next') {
        // Deliberately forget the last sent value so that we don't
        // accidentally pass it on to the delegate.
        this.arg = undefined
      }

      return ContinueSentinel
    }
  }

  // Regardless of whether this script is executing as a CommonJS module
  // or not, return the runtime object so that we can declare the variable
  // regeneratorRuntime in the outer scope, which allows this module to be
  // injected easily by `bin/regenerator --include-runtime script.js`.
  return exports
}(
  // If this script is executing as a CommonJS module, use module.exports
  // as the regeneratorRuntime namespace. Otherwise create a new empty
  // object. Either way, the resulting object will be used to initialize
  // the regeneratorRuntime variable at the top of this file.
  typeof module === 'object' ? module.exports : {}))
